﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Metadata.Edm;

namespace TesteT4
{
    // Set recordRequiredOriginalValuesOnly to false in the OriginalValueMembers constructor in order to always record all original values
    public class OriginalValueMembers
    {
        private readonly HashSet<EdmProperty> _concurrencyMembers;

        public OriginalValueMembers(bool recordRequiredOriginalValuesOnly, MetadataWorkspace metadataWorkspace, MetadataTools metadataTools)
        {
            if (recordRequiredOriginalValuesOnly)
            {
                try
                {
                    _concurrencyMembers = new HashSet<EdmProperty>();
                    foreach (EntityContainer container in metadataWorkspace.GetItems<EntityContainer>(DataSpace.CSpace))
                    {
                        ILookup<EntityType, EntityType> directSubTypeLookup = metadataWorkspace.GetItems<EntityType>(DataSpace.CSpace).ToLookup(e => (EntityType)e.BaseType);
                        foreach (EntitySetBase eSet in container.BaseEntitySets.Where(es => es.BuiltInTypeKind == BuiltInTypeKind.EntitySet))
                        {
                            List<EntityType> subTypes = new List<EntityType>();
                            GetSubtypes(directSubTypeLookup, (EntityType)eSet.ElementType, subTypes);
                            foreach (EntityType eType in subTypes)
                            {
                                foreach (EdmProperty member in metadataWorkspace.GetRequiredOriginalValueMembers(eSet, eType))
                                {
                                    _concurrencyMembers.Add(member);
                                }
                            }
                        }
                    }

                    // GetRequiredOriginalValueMembers will not always return foreign key properties, but they are required
                    foreach (AssociationType assoc in metadataWorkspace.GetItems<AssociationType>(DataSpace.CSpace).Where(a => a.IsForeignKey))
                    {
                        foreach (EdmProperty toProperty in assoc.ReferentialConstraints[0].ToProperties)
                        {
                            _concurrencyMembers.Add(toProperty);
                        }
                    }
                }
                catch (Exception)
                {
                    // If any exceptions occur, fall back to always recording original values for all properties
                    _concurrencyMembers = null;
                }
            }
        }

        public bool IsOriginalValueMember(EdmProperty edmProperty)
        {
            return _concurrencyMembers == null || _concurrencyMembers.Contains(edmProperty);
        }

        private static void GetSubtypes(ILookup<EntityType, EntityType> lookup, EntityType eType, List<EntityType> subTypes)
        {
            subTypes.Add(eType);
            foreach (EntityType subType in lookup[eType])
            {
                GetSubtypes(lookup, subType, subTypes);
            }
        }
    }


}
